const PEDDING = 'pedding'
const RESOLVED = 'fulfilled'
const REJECTED = 'rejected'

function MyPromise(this: any, fn: Function) {
    const self = this

    this.state = PEDDING
    this.value = null
    this.resolvedCallbacks = []
    this.rejectedCallbacks = []

    function resolve(this: any, value: any) {
        if(value instanceof MyPromise) {
            return (value as any).then(resolve, reject)
        }
        setTimeout(() => {
            if(self.state === PEDDING) {
                self.state = RESOLVED
                self.value = value
                while(self.rejectedCallbacks.length) {
                    self.rejectedCallbacks.shift()(value)
                }      
            }
        }, 0)
    }

    function reject(this: any, reason: any) {
        setTimeout(() => {
            if(self.state === PEDDING) {
                self.state = REJECTED
                self.value = reason
                while(self.rejectedCallbacks.length) {
                    self.rejectedCallbacks.shift()(reason)
                }      
            }
        }, 0)    
    }

    try {
        fn(resolve, reject)
    } catch(err: any) {
        reject(err)
    }
}

MyPromise.prototype.then = function(this: any, onResolved: any, onRejected: any) {
    if(this.state === PEDDING) {
        this.resolvedCallbacks.push(onResolved)
        this.rejectedCallbacks.push(onRejected)
    }
    if(this.state === RESOLVED) {
        onResolved(this.value)
    }
    if(this.state === PEDDING) {
        onRejected(this.value)
    }
}

const p = new (MyPromise as any)((resolve: any, reject: any) => {
    resolve('success')
    // reject('here is an error')
})

p.then((res: any) => {
    console.log(res)
}, (reason: any) => {
    console.log(reason)
})

export {}